%{
#define _BSD_SOURCE

#include <string.h>
#include <stdlib.h>
//#include <stdarg.h>


//int fileno(FILE *stream);

#define YY_EXTRA_TYPE struct Buffer *

#define ECHO yyextra->y = yytext; while(*yyextra->y) *(yyextra->b++) = *(yyextra->y++); *(yyextra->b) = 0;


struct Buffer {
	char *buf;
	char *b, *y;
	size_t len;
	int lineno, last_lineno;
};

static void nl(YY_EXTRA_TYPE extra){
	switch(extra->lineno - extra->last_lineno){
		case 0: case 1:
			break;
		default:
			*extra->b = 0;
			extra->b += sprintf(extra->b, "//@line %i\n", extra->lineno);
	}
	extra->last_lineno = extra->lineno;
}


%}

%option 8bit
%option extra-type="struct Buffer *"
%option noyywrap
%option reentrant

%x dqstring qstring block_comment

%%

"\n"        ECHO; ++yyextra->lineno; nl(yyextra); BEGIN(INITIAL);

"\""  ECHO; BEGIN(dqstring);
"\'"  ECHO; BEGIN(qstring);


"/""/"[^\n]*   ++yyextra->lineno; BEGIN(INITIAL);
^"#"[^\n]*     ++yyextra->lineno; BEGIN(INITIAL);
"/""*"		BEGIN(block_comment);



<dqstring>"\\."  ECHO; BEGIN(dqstring);
<dqstring>"\n"   *(yyextra->b++) = '\\'; *(yyextra->b++) = 'n'; ++yyextra->lineno; BEGIN(dqstring);
<dqstring>"\""   ECHO; BEGIN(INITIAL);

<qstring>"\\."  ECHO; BEGIN(qstring);
<qstring>"\n"   *(yyextra->b++) = '\\'; *(yyextra->b++) = 'n'; ++yyextra->lineno; BEGIN(qstring);
<qstring>"\'"   ECHO; BEGIN(INITIAL);

<block_comment>"*/"    BEGIN(INITIAL);
<block_comment>"\n"    ++yyextra->lineno; BEGIN(block_comment);
<block_comment>.       BEGIN(block_comment);


[\xC0-\xDF][\x80-\xBF]             sprintf(yyextra->b, "\\u%04X", ((yytext[0] & 0x1F) << 6) | (yytext[1] & 0x3F)); yyextra->b += 6;
[\xE0-\xEF][\x80-\xBF][\x80-\xBF]  sprintf(yyextra->b, "\\u%04X", ((yytext[0] & 0x0F) << 12) | ((yytext[1] & 0x3F) << 6) | (yytext[2] & 0x3F)); yyextra->b += 6;


%%


int js_preprocess_string(char *buf, size_t len, char *str) {
	struct Buffer *oB = (struct Buffer *)malloc(sizeof(struct Buffer));
	oB->buf = buf;
	oB->b = buf;
	oB->len = len;
	oB->lineno = 1;
	oB->last_lineno = 0;
		
	yyscan_t scanner;
	yylex_init(&scanner);

	yyset_extra(oB, scanner);
	YY_BUFFER_STATE s = yy_scan_string(str, scanner);
	yy_switch_to_buffer(s, scanner);
	
	yylex(scanner);
	yylex_destroy(scanner);
	
	*oB->b = 0;
}


int js_preprocess(char *buf, size_t len, FILE *stream) {
	struct Buffer *oB = (struct Buffer *)malloc(sizeof(struct Buffer));
	oB->buf = buf;
	oB->b = buf;
	oB->len = len;
	oB->lineno = 1;
	oB->last_lineno = 0;
		
	yyscan_t scanner;
	yylex_init(&scanner);

	yyset_extra(oB, scanner);
	yyset_in(stream, scanner);

	yylex(scanner);
	yylex_destroy(scanner);
}


